/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
 */

package controllers

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"io/ioutil"
	"prim-server/common"
	"prim-server/errcode"
	"prim-server/logger"
	samlService "prim-server/service/saml"

	"github.com/beevik/etree"
	"github.com/crewjam/saml"
	"github.com/klauspost/compress/flate"
)

const (
	SamlLoginURL = "/v1/saml/login"
)

type SSOController struct {
	CommonController
}

func (nc *SSOController) SAMLLogin() {
	//读取IAM SAML转发请求
	query := common.SAMLRequest{}
	if err := json.Unmarshal(nc.Ctx.Input.RequestBody, &query); err != nil {
		logger.Error("SAMLLogin Unmarshal error: %v", err)
		nc.HandleErrCode(errcode.E.Base.RequestInvalid.WithErr(err))
		return
	}
	//解析samlRequest
	decodeedSAMLRequest, err := base64.StdEncoding.DecodeString(query.SAMLRequest)
	if err != nil {
		logger.Error("SAMLLogin error: %v", err)
		return
	}
	samlRequestData, err := ioutil.ReadAll(flate.NewReader(bytes.NewReader(decodeedSAMLRequest)))
	if err != nil {
		logger.Error("SAMLLogin error: %v", err)
		return
	}
	var samlRequest saml.AuthnRequest
	err = xml.Unmarshal(samlRequestData, &samlRequest)
	if err != nil {
		logger.Error("SAMLLogin error: %v", err)
		return
	}
	spMetadata, err := samlService.GetSpMetaData()
	if err != nil {
		logger.Error("getSpMetaData error: %v", err)
		return
	}
	//SAML验签--暂时忽略验证结果
	err = samlService.VerifySignature(spMetadata, query)
	if err != nil {
		logger.Warn("verifySignature error: %v", err)
	}
	//生成SAMLResponse
	samlResponse, err := samlService.BuildSamlResponse(samlRequest, spMetadata, query.UserId)
	if err != nil {
		logger.Error("buildSamlResponse error: %v", err)
		return
	}
	nc.RedirectF(samlRequest.AssertionConsumerServiceURL, query.RelayState, samlResponse)
}
func (nc *SSOController) RedirectF(assertionConsumerUrl, relayState string, samlResponse *etree.Element) {
	//post请求应答路径
	doc := etree.NewDocument()
	doc.SetRoot(samlResponse)
	responseBuf, err := doc.WriteToBytes()
	if err != nil {
		return
	}
	postResponse := base64.StdEncoding.EncodeToString(responseBuf)
	//重定向--直接返回
	redirect := common.SAMLResponse{
		AssertionConsumerUrl: assertionConsumerUrl,
		RelayState:           relayState,
		SAMLResponse:         postResponse,
	}
	nc.HandleBusinessObj(redirect)
}
